/**
* 根据账号id获取所有角色信息
* @param uid 账号id
*/
export async function get_characters_by_accounts_id(uid) {
    return await _database_.execute_query_list(`
        select * from characters where uid = ${uid} order by id asc;
    `)
};

/**
 *  存入角色数据
 * @param uid uid
 * @param characters_name 角色名
 * @param json_data 角色详细信息
 * @returns 角色信息
 */
export async function insert_characters_data(uid, characters_name, json_data) {
    json_data["uid"] = uid;
    let id = await _database_.execute_insert(`
        INSERT INTO "characters" 
        (uid, characters_name, json_data) 
        VALUES
        (
        ${uid}, 
        '${characters_name}',
        '${JSON.stringify(json_data)}'
        );
    `)
    if (Number(id) !== 0) {
        json_data["id"] = Number(id);
        await update_characters_data(Number(id), characters_name, JSON.stringify(json_data));
        return await _database_.execute_query_one(
            `
            select * from characters where id = ${id}
            `
        );
    } else {
        return "";
    }
};

/**
 *  更新数据库的角色数据
 * @param characters_id 角色id
 * @param characters_name 角色名
 * @param json_data 角色详细信息 字符串
 * @returns 角色信息
 */
export async function update_characters_data(characters_id, characters_name, json_data) {
    await _database_.execute_update(`
        UPDATE "characters" SET characters_name='`+ characters_name + `', json_data='` + json_data + `' WHERE id=` + characters_id + `;
        `);
};

/**
 *  使用json_data更新数据库的角色数据
 * @param characters_id 角色id
 * @param characters_name 角色名
 * @param json_data 角色详细信息 JSON格式
 * @returns 角色信息
 */
export async function update_characters_data_by_json_data(json_data) {
    await _database_.execute_update(`
            UPDATE "characters" SET characters_name='${json_data["名称"]}', json_data='${JSON.stringify(json_data)}' WHERE id=${json_data["id"]}
    `);
    await G.CharactersTask.save_characters_task(json_data["id"]);
};


/**
 * 多背包之间移动物品
 * @param {*} characters_id 
 * @param {*} src_key  背包类型
 * @param {*} src_index 背包内的位置
 * @param {*} target_key 目标背包
 * @param {*} target_index 目标背包位置
 * @returns 
 */
export function move_item(characters_id, src_key, target_key, src_index, target_index) {
    let characters = _CharactersData.get(characters_id);
    let character_client_id = get_characters_client_id(characters_id);
    //原背包
    let key_values = characters[src_key];
    if (key_values === undefined) {
        if (character_client_id !== undefined) {
            //发送通知
            ClientUtils.send_basic_prompt(character_client_id, `${src_key}背包不存在`);
        }
        return false;
    }
    if (key_values[src_index] === undefined || key_values[src_index] === null) {
        if (character_client_id !== undefined) {
            //发送通知
            ClientUtils.send_basic_prompt(character_client_id, `该位置不存在物品`);
        }
        return false;
    }
    if (src_key === target_key) {
        //同背包移动
        G.ItemsUils.move_item_to_items_index(key_values, src_index, target_index);
        characters[src_key] = key_values;
    } else {
        //跨背包移动
        //获取目标背包
        let target_key_values = characters[target_key];
        if (target_index === -1) {
            //寻找一个空位
            for (let index = 0; index < target_key_values.length; index++) {
                if (target_key_values[index] === null || target_key_values[index] === undefined) {
                    target_index = index;
                    break;
                }
            }
            //如果目标背包是空的或者没有空位
            target_index = target_index !== -1 ? target_index : target_key_values.length;
        }
        G.ItemsUils.move_src_items_item_to_target_items_idnex(key_values, target_key_values, src_index, target_index);
    }
    if (character_client_id !== undefined) {
        if (target_key === "法宝" || target_key === "神器" || target_key === "灵宝") {
            refrush_fabao_data(characters);
        } else {
            //通知客户端主动更新背包
            ClientUtils.send_client_message(character_client_id, 3699, 1);
        }
    }
    return true
}

/**
 * 整理背包
 * @param {*} characters_id 
 * @param {*} type_key 目标包裹
 */
export function sort_items(characters_id, type_key) {
    let characters = _CharactersData.get(characters_id);
    let character_client_id = get_characters_client_id(characters_id);
    let key_values = characters[type_key];
    if (key_values === undefined) {
        if (character_client_id !== undefined) {
            //发送通知
            ClientUtils.send_basic_prompt(character_client_id, `${type_key}背包不存在`);
        }
        return false;
    }
    //简单排序去除空格
    let tmp_list = [];
    for (let index = 0; index < key_values.length; index++) {
        if (key_values[index] !== undefined && key_values[index] !== null) {
            tmp_list.push(key_values[index]);
        }
    }
    characters[type_key] = tmp_list;
    if (character_client_id !== undefined) {
        ClientUtils.send_client_message(character_client_id, 3699, 1);
    }
}

/**
 * 移除背包物品
 * @param {*} characters_id 
 * @param {*} key  背包类型
 * @param {*} index 背包内的位置
 * @returns 
 */
export function remove_item(characters_id, key, index, num = 9999) {
    let characters = _CharactersData.get(characters_id);
    let items = characters[key];
    let character_client_id = get_characters_client_id(characters_id);
    if (items === undefined) {
        if (character_client_id !== undefined) {
            //发送通知
            ClientUtils.send_basic_prompt(character_client_id, `${key}位置不存在`);
        }
        return false;
    }
    if (items[index] === undefined || items[index] === null) {
        ClientUtils.send_basic_prompt(character_client_id, `该位置不存在物品`);
        return false;
    }
    let item_name = items[index]["名称"];
    let item_num = 1;
    if (items[index]["数量"]) {
        if (items[index]["数量"] <= num) {
            item_num = items[index]["数量"];
            items[index] = null;
        } else {
            item_num = num;
            items[index]["数量"] -= num;
        }
    } else {
        items[index] = null;
        characters[key] = items;
    }
    if (character_client_id !== undefined) {
        ClientUtils.send_client_message(character_client_id, 3699, 1);
        G.ChatUtils.send_system_chat(character_client_id, `失去物品 #G${item_name}#x#Y${item_num}`)
    }
    return true;
}

/**
 * 脱下装备
 * @param {*} characters_id 
 * @param {*} key 类型 装备 灵饰 锦衣
 * @param {*} items_key 背包类型
 * @param {*} index 装备下标
 */
export function take_off_equipment(characters_id, key, items_key, index) {
    let characters = _CharactersData.get(characters_id);
    let equipments = characters[key];
    if (equipments !== undefined) {
        let equipment = equipments[index];
        if (equipment !== undefined) {
            //放入背包
            let items = characters[items_key];
            G.ItemsUils.add_item_to_items(items, equipments[index], 1);
            characters[items_key] = items;
            //移除装备位
            equipments[index] = null;
            //更新装备位
            characters[key] = equipments;
            let character_client_id = get_characters_client_id(characters_id);
            if (key === "装备") {
                if (character_client_id !== undefined) {
                    //通知客户端更新信息
                    ClientUtils.send_client_message(character_client_id, 3503, characters["装备"]);
                    ClientUtils.send_client_message(character_client_id, 3699, 1);
                }
            }
            if (key === "锦衣") {
                if (character_client_id !== undefined) {
                    //通知客户端更新信息
                    ClientUtils.send_client_message(character_client_id, 3703, characters["锦衣"]);
                    ClientUtils.send_client_message(character_client_id, 3704, 1);
                    ClientUtils.send_client_message(character_client_id, 3699, 1);

                    G.MapUtils.update_fashion(characters_id, index);
                    ClientUtils.send_client_message(character_client_id, 12, 1);

                }
            }
            if (key === "灵饰") {
                if (character_client_id !== undefined) {
                    //通知客户端更新信息
                    ClientUtils.send_client_message(character_client_id, 3506, characters["灵饰"]);
                    ClientUtils.send_client_message(character_client_id, 3699, 1);
                    refrush_hp_data(characters_id);
                    ClientUtils.send_client_message(character_client_id, 12, 1);

                }
            }
            refrush_characters_data(characters);
        }
    }
}

/**
 * 穿装备
 * @param {*} characters_id 
 * @param {*} key 背包类型
 * @param {*} index 装备在背包内的位置
 * @returns 
 */
export function wear_equipment(characters_id, key, index) {

    let characters = _CharactersData.get(characters_id);
    let character_client_id = get_characters_client_id(characters_id);
    let key_values = characters[key];
    if (key_values === undefined) {
        if (character_client_id !== undefined) {
            ClientUtils.send_basic_prompt(character_client_id, `#R角色的${key}背包不存在`);
        }
        return false;
    }
    let item = key_values[index];
    if (item === undefined || item === null) {
        ClientUtils.send_client_message(character_client_id, `#R${key}背包内不存在该物品`);
        return false;
    }
    let equipment_type_data = G.ItemUtils.get_item_equipment_type(item);
    //装备位置类型
    let equipment_master_type = equipment_type_data[0];
    if (equipment_master_type === "召唤兽") {
        if (character_client_id !== undefined) {
            //通知客户端更新信息
            ClientUtils.send_basic_prompt(character_client_id, "角色不能佩戴召唤兽装备");
            return;
        }
    }
    //装备位置
    let equipment_index = Number(equipment_type_data[2]);
    //装备总位置大小
    let equipment_index_size = Number(equipment_type_data[3]);
    //所有装备
    let equipments = characters[equipment_master_type];
    if (equipments === undefined || equipments.length === 0) {
        //初始化装备位置
        equipments = [];
        for (let index = 0; index < equipment_index_size; index++) {
            equipments.push(null);
        }
    }

    //已装备或为空都替换背包原来的位置

    let equipment = {};
    if (equipments[equipment_index] === undefined || equipments[equipment_index] === null) {
        equipment = null
    } else {
        Object.assign(equipment, equipments[equipment_index]);
    }

    let new_equipment = {};
    Object.assign(new_equipment, item);

    //更新背包
    key_values[index] = equipment;
    characters[key] = key_values;

    //穿戴装备到指定位置
    equipments[equipment_index] = new_equipment;
    characters[equipment_master_type] = equipments;

    // 更新角色缓存

    if (equipment_master_type === "装备") {
        if (character_client_id !== undefined) {
            //通知客户端更新信息
            ClientUtils.send_client_message(character_client_id, 3503, characters["装备"]);
            ClientUtils.send_client_message(character_client_id, 3699, 1);
        }
    }

    if (equipment_master_type === "锦衣") {
        if (character_client_id !== undefined) {
            //通知客户端更新信息

            ClientUtils.send_client_message(character_client_id, 3703, characters["锦衣"]);
            ClientUtils.send_client_message(character_client_id, 3704, 1);
            ClientUtils.send_client_message(character_client_id, 3699, 1);

            G.MapUtils.update_fashion(characters_id, equipment_index);
            ClientUtils.send_client_message(character_client_id, 12, 1);
        }
    }
    if (equipment_master_type === "灵饰") {
        if (character_client_id !== undefined) {
            //通知客户端更新信息
            ClientUtils.send_client_message(character_client_id, 3506, characters["灵饰"]);
            ClientUtils.send_client_message(character_client_id, 3699, 1);
            refrush_hp_data(characters_id);
            ClientUtils.send_client_message(character_client_id, 12, 1);
        }
    }
    refrush_characters_data(characters);
}

/**
 * 添加召唤兽
 */
export function add_pet(characters_id, pet_name) {
    let pet_data = G.Pet.build_pet_data(pet_name);
    if (pet_data !== undefined) {
        let characters = _CharactersData.get(characters_id);
        let client_id = get_characters_client_id(characters["id"]);
        if (characters["召唤兽"].length >= characters["召唤兽携带上限"]) {
            if (client_id !== undefined) {
                ClientUtils.send_basic_prompt(client_id, "无法携带更多宠物");
            }
            return;
        }
        pet_data["认证码"] = `${characters_id}_${pet_data["认证码"]}`;
        characters["召唤兽"].push(pet_data);
        if (client_id !== undefined) {
            ClientUtils.send_client_message(client_id, 16, characters["召唤兽"]);
        }
    }
}

/**
 * 添加坐骑
 */
export function add_mounts(characters_id, mounts_name) {
    let mounts_data = G.Mounts.build_mounts_data(mounts_name);
    if (mounts_data !== undefined) {
        let characters = _CharactersData.get(characters_id);
        let client_id = get_characters_client_id(characters["id"]);
        if (characters["坐骑列表"].length >= 6) {
            if (client_id !== undefined) {
                ClientUtils.send_basic_prompt(client_id, "无法携带更多坐骑");
            }
            return;
        }
        mounts_data["认证码"] = `${characters_id}_${mounts_data["认证码"]}`;
        characters["坐骑列表"].push(mounts_data);
        if (client_id !== undefined) {
            ClientUtils.send_client_message(client_id, 61, characters["坐骑列表"]);
        }
    }
}

/**
 * 为角色批量添加道具并向所有人发送系统频道超链接消息
 * @param {*} characters_id 
 * @param {*} item_name_list 
 * @param {*} link_text_data 
 */
export function batch_add_item_and_send_url(characters_id, item_name_list, link_text_data) {
    for (let index = 0; index < item_name_list.length; index++) {
        let element = item_name_list[index];
        let item_name = element[0];
        let num = element[1];
        add_item_and_send_url(characters_id, item_name, num, link_text_data);
    }
}

/**
*  为角色添加道具并向所有人发送系统频道超链接消息
*/
export function add_item_and_send_url(characters_id, item_name, num, link_text_data, production_type = "系统") {
    if (item_name === undefined) {
        console.warn(`道具名称为空`)
        return;
    }
    let item_data = add_item(characters_id, item_name, num, production_type);
    let url_text = G.ChatUtils.build_url_text(item_data, "道具");
    let text = `${link_text_data["提示"]}${url_text}${link_text_data["结尾"]}`;
    item_data["索引类型"] = "道具";
    G.ChatUtils.send_all_sytem_url_chat(text, [item_data]);
}

/**
*  为角色添加道具 兼容原体系，使用物品名称添加
*/
export function add_item(characters_id, item_name, num, production_type = "系统") {
    if (item_name === undefined) {
        console.warn(`道具名称为空`)
        return;
    }
    let characters = _CharactersData.get(characters_id);
    if (production_type === undefined) {
        production_type = "系统";
    }
    //生成物品
    let item_data = G.ItemUtils.generate_item_data(item_name, production_type);
    if (item_data === undefined) {
        return undefined;
    }
    let target_key = "道具";
    switch (item_data["物品类型"]) {
        case "法宝":
            target_key = "法宝";
            break;
        case "灵宝":
            target_key = "灵宝";
            break;
        default:
            break;
    }
    if (item_data !== undefined) {
        //道具背包为空则初始化一下
        if (characters[target_key] === undefined) {
            characters[target_key] = [];
        }
        let items = characters[target_key];
        //放入背包
        G.ItemsUils.add_item_to_items(items, item_data, num);
        let character_client_id = get_characters_client_id(characters_id);
        if (character_client_id !== undefined) {
            //发送通知
            if (target_key === "法宝" || target_key === "灵宝") {
                refrush_fabao_data(characters);
                ClientUtils.send_basic_prompt(character_client_id, `获得 ${target_key}#G${item_name}x#Y${num}`);
            } else {
                ClientUtils.send_basic_prompt(character_client_id, `获得#G${item_name}#x#Y${num}`);
                G.ChatUtils.send_system_chat(character_client_id, `获得#G${item_name}#x#Y${num}`);
                ClientUtils.send_client_message(character_client_id, 3699, 1);
            }
        }
    }
    return item_data;
}

/**
 * 创建角色
 * @param {*} uid 
 * @param {*} username 
 * @param {*} characters_name 
 * @param {*} characters_type 
 * @param {*} characters_color 
 * @returns 
 */
export async function create_characters(client_id, uid, username, characters_name, characters_type, characters_color) {
    let res = await _database_.execute_query_list(`select * from characters where characters_name = '${characters_name}';`);
    if (JSON.parse(res).length >= 1) {
        ClientUtils.send_basic_prompt(client_id, "#这个名称已经被他人占用了，请重新再想个吧");
        return "";
    }
    //开始角色创建逻辑
    let characters_data = build_characters_data(username, characters_name, characters_type, characters_color);
    //角色数据存入数据库
    let new_characters = await insert_characters_data(uid, characters_name, characters_data);

    if (new_characters.length > 0) {
        //缓存新创建的角色信息
        let new_characters_json = JSON.parse(new_characters);
        _CharactersData.set(new_characters_json["id"], JSON.parse(new_characters_json.json_data));
        let ids = _UserNameCidsData.get(username);
        if (ids !== undefined) {
            ids.push(new_characters_json["id"]);
        }
        return new_characters_json;
    }
    return new_characters;
}

/**
*  加载角色信息并通知客户端跳到角色选择界面
*  @param {*} client_id 
*  @param {*} uid 
*  @param {*} username 
*/
export async function load_characters(client_id, uid, username) {
    let all_characters_str = await get_characters_by_accounts_id(uid);
    let all_characters = [];
    if (all_characters_str !== "") {
        all_characters = JSON.parse(all_characters_str);
        // 加载角色任务数据
        for (let index = 0; index < all_characters.length; index++) {
            await G.CharactersTask.load_characters_task(all_characters[index]["id"]);
        }
        //缓存所有角色信息
        set_all_characters(username, all_characters);
    }

    let end_data = [];
    all_characters.forEach(v => {
        let v_json = JSON.parse(v.json_data);
        let master = { "名称": "", "级别限制": 0, "子类": 0 };
        let slave = { "名称": "", "级别限制": 0, "子类": 0 }
        end_data.push({
            "名称": v_json["名称"],
            "武器数据": master,
            "副武器数据": slave,
            "等级": v_json["等级"],
            "炫彩": v_json["炫彩"],
            "炫彩组": v_json["炫彩组"],
            "染色方案": v_json["染色方案"],
            "染色组": v_json["染色组"],
            "造型": v_json["造型"],
            "门派": v_json["门派"],
            "id": v_json["id"],
        });
    });

    ClientUtils.send_client_message(client_id, 4, end_data);
}


/**
* 缓存账户所有角色
*/
export function set_all_characters(username, all_characters) {
    let ids = [];
    all_characters.forEach(characters => {
        let data = JSON.parse(characters.json_data);
        _CharactersData.set(data["id"], data);
        ids.push(data["id"]);
    });
    _UserNameCidsData.set(username, ids);
}

/**
* 获取账户所有角色
* @returns 
*/
export function get_all_characters(username) {
    let ids = _UserNameCidsData.get(username);
    let data = [];
    if (ids !== undefined) {
        ids.forEach(id => {
            let characters = _CharactersData.get(id);
            if (characters !== undefined) {
                data.push(characters);
            }
        });
    }
    return data;
}

/**
 * 删除所有角色缓存
 * @param {*} username 
 */
export function remove_all_characters_cache(username) {
    let ids = _UserNameCidsData.get(username);
    if (ids !== undefined) {
        ids.forEach(id => {
            _CharactersTradeData.delete(id);
            _LastDialogueData.delete(id);
            logout_characters(id);
            _CharactersData.delete(id);
            _CharactersClientData.delete(id);
            _OnlineCharactersData.delete(id);
            _MasterCharactersData.delete(id);
            _CharactersTaskData.delete(id);
        });
    }
    _UserNameCidsData.delete(username);
}

/**
*  获取本次登录的主角色
* @return 角色信息
*/
export function get_current_login_characters(client_id) {
    let characters_id = _MasterCharactersData.get(client_id);
    if (characters_id !== undefined) {
        return _CharactersData.get(characters_id);
    }
    return undefined;
}

/**
*  根据id加载角色信息并缓存登录 （主角色登录）
* @param characters_id 角色id
*/
export function master_login(client_id, username, characters_id) {
    let all_characters = get_all_characters(username);
    let login_characters;
    for (let characters of all_characters) {
        if (characters["id"] === characters_id) {
            login_characters = characters;
            break;
        }
    }
    if (login_characters !== undefined) {
        //缓存客户端id
        _CharactersClientData.set(login_characters["id"], client_id);
        //设置角色在线
        set_characters_online(login_characters["id"]);
        //保存主角色标识
        _MasterCharactersData.set(client_id, login_characters["id"]);
    }
    G.EventCallback.publish_event("进入游戏", [client_id, login_characters]);
    return login_characters;
}

/**
 * 切换当前登录角色
 * @param {*} characters 
 */
export function reset_master_login(client_id, characters) {
    if (characters !== undefined) {
        let master_characters = get_current_login_characters(client_id);
        // TODO 取消当前登录角色正在进行的交易
        _CharactersTradeData.delete(master_characters["id"]);
        //删除原客户端缓存
        _CharactersClientData.delete(master_characters["id"]);
        //缓存客户端id
        _CharactersClientData.set(characters["id"], client_id);
        //设置角色在线
        set_characters_online(characters["id"]);
        //保存主角色标识
        _MasterCharactersData.set(client_id, characters["id"]);
        //发送登录数据
        send_login_characters_data(client_id, characters);
        //切换助战队长
        G.TeamUtils.update_help_fight_leader(client_id, master_characters, characters);
        // 更新助战列表
        let send_data = G.HelpFight.get_help_fight_list(client_id);
        ClientUtils.send_client_message(client_id, 2002, send_data);
        G.EventCallback.publish_event("切换角色", [client_id, characters]);
    }
}

/**
 * 发送角色登录数据
 * @param {*} client_id 
 * @param {*} characters 
 */
export function send_login_characters_data(client_id, characters) {
    // 处理过期任务
    G.CharactersTask.check_timout_task(characters["id"]);
    //发送角色总数据
    ClientUtils.send_client_message(client_id, 5, G.Characters.computing_characters_data(characters));
    //下发道具和存银数据
    let send_item_data = {
        "银子": characters["银子"],
        "储备": characters["储备"],
        "存银": characters["存银"],
        "道具": characters["道具"]
    }
    ClientUtils.send_client_message(client_id, 200, send_item_data);
    //下发召唤兽数据
    ClientUtils.send_client_message(client_id, 16, characters["召唤兽"]);

    // 下发宝宝技能图
    let send_bb_dw_data = { "雷属性吸收": 166, "弱点水": 262, "慧根": 159, "欣欣向荣": 201, "善恶有报": 123, "夜战": 292, "龙魂": 181, "高级必杀": 100, "薪火相传": 223, "超级感知": 45, "特色善恶有报": 219, "超级飞行": 214, "观照万象": 85, "扶摇万里": 86, "独行": 213, "超级水漫金山": 219, "从天而降": 106, "高级永恒": 218, "高级神迹": 12, "土属性吸收": 214, "超级驱鬼": 214, "冥思": 195, "火属性吸收": 81, "移花接木": 178, "高级雷属性吸收": 113, "弱点火": 109, "法术反震": 81, "反击": 77, "势如破竹": 198, "遗志": 73, "必杀": 212, "力劈华山": 210, "流沙轻音": 15, "超级奔雷咒": 58, "超级神迹": 252, "超级盾气": 176, "月光": 200, "超级冥思": 249, "水漫金山": 189, "水攻": 68, "超级否定信仰": 162, "超级隐身": 267, "超级防御": 238, "超级招架": 223, "水击三千": 73, "超级法术连击": 225, "剑荡四方": 148, "高级反击": 191, "落岩": 129, "浮云神马": 7, "桀骜自恃": 103, "弱点土": 298, "超级反震": 90, "进阶必杀": 291, "高级合纵": 287, "招架": 259, "高级招架": 37, "理直气壮": 3, "超级精神集中": 210, "千钧一怒": 281, "超级火属性吸收": 277, "神佑复生": 241, "超级夜战": 276, "神来气旺": 86, "高级法术抵抗": 272, "柳暗花明": 271, "法术波动": 99, "北冥之渊": 269, "超级遗志": 269, "逍遥游": 259, "食指大动": 243, "偷袭": 103, "驱鬼": 187, "防御": 191, "感知": 162, "高级幸运": 213, "超级泰山压顶": 152, "虎虎生风": 94, "连击": 39, "毒": 162, "高级防御": 109, "否定信仰": 79, "高级盾气": 173, "高级感知": 234, "净台妙谛": 271, "须弥真言": 116, "法术暴击": 204, "高级精神集中": 143, "再生": 291, "高级进阶必杀": 153, "灵山禅语": 239, "凝光炼彩": 43, "高级土属性吸收": 154, "盾气": 90, "魔之心": 29, "与生俱来": 52, "高级毒": 129, "超级连击": 152, "高级火属性吸收": 129, "无畏布施": 193, "高级魔之心": 57, "高级强力": 49, "超级进阶必杀": 163, "弱点雷": 51, "超级法术暴击": 300, "好梦连连": 299, "高级冥思": 152, "高级驱鬼": 263, "超级敏捷": 10, "高级吸血": 298, "烈火": 116, "高级否定信仰": 105, "苍鸾怒击": 295, "超级吸血": 234, "风起龙游": 271, "超级法术抵抗": 295, "凭风借力": 232, "高级偷袭": 294, "法术抵抗": 140, "气贯长虹": 93, "超级永恒": 209, "超级慧根": 165, "高级夜战": 102, "高级飞行": 194, "嗜血追击": 191, "高级进阶法爆": 33, "高级连击": 20, "泰山压顶": 152, "高级法术波动": 101, "超级再生": 121, "地狱烈火": 1, "法术连击": 7, "灵能激发": 62, "天降灵葫": 296, "超级土属性吸收": 6, "超级雷属性吸收": 122, "高级法术连击": 45, "高级神佑复生": 45, "超级神柚复生": 114, "超级法术波动": 117, "合纵": 24, "圣婴大王": 124, "大快朵颐": 35, "超级强力": 131, "幸运": 18, "无上正真": 223, "高级鬼魂术": 223, "八凶法阵": 298, "雷击": 56, "超级三昧真火": 117, "超级偷袭": 191, "精神集中": 127, "奔雷咒": 140, "高级再生": 111, "高级隐身": 190, "迟钝": 41, "高级水属性吸收": 81, "死亡召唤": 136, "昼伏夜出": 43, "法术防御": 36, "义薄云天": 242, "水属性吸收": 56, "超级壁垒击破": 293, "永恒": 97, "上古灵符": 74, "超级幸运": 198, "反震": 165, "超级水属性吸收": 267, "鬼魂术": 277, "迅风出击": 201, "高级敏捷": 168, "隐身": 207, "超级合纵": 46, "高级反震": 88, "津津有味": 210, "叱咤风云": 190, "敏捷": 189, "惊心一剑": 36, "超级反击": 248, "飞行": 117, "超级进阶法爆": 246, "超级毒": 244, "神出鬼没": 244, "法力陷阱": 130, "吸血": 255, "出其不意": 6, "高级遗志": 237, "夜舞倾城": 235, "狂莽一击": 233, "高级法术暴击": 233, "神迹": 230, "高级慧根": 229, "溜之大吉": 197, "超级魔之心": 105, "超级地狱烈火": 228, "高级独行": 170, "壁垒击破": 225, "强力": 50, "进阶法爆": 5, "超级必杀": 85 };
    ClientUtils.send_client_message(client_id, 25, send_bb_dw_data);

    // 通知客户端
    let send_todo_data = {
        "id": characters["id"],
        "用户": "正式用户",
        "名称": characters["名称"],
        "账号": characters["账号"]
    }
    ClientUtils.send_client_message(client_id, 997, send_todo_data);
    // 发送时辰和天气数据
    ClientUtils.send_client_message(client_id, 443, _SystemHourData["天气"]);
    ClientUtils.send_client_message(client_id, 43, _SystemHourData["昼夜"]);
    ClientUtils.send_client_message(client_id, 11, _SystemHourData["当前"]);

    // 刷新商城数据
    ClientUtils.send_client_message(client_id, 3705, G.ShoppingMallData.default);

    // 发送新号弹窗
    if (characters["新号"] === 1) {
        ClientUtils.send_client_message(client_id, 105, { "头像": "双蓝字", "标题": "出生于桃源村！", "说明": "首次登陆游戏，快去完成新手剧情吧" });
        characters["新号"] = 0;
    }

    // 向地图内加入玩家
    G.MapUtils.add_characters(characters["地图数据"]["编号"], characters);

    //发送角色剧情
    ClientUtils.send_client_message(client_id, 227, characters["剧情"]);

    // 刷新任务数据
    G.CharactersTask.refrush_task(characters["id"]);

    // 快捷技能栏刷新
    ClientUtils.send_client_message(client_id, 42, "");
}

/**
 * 获取角色的客户端id
 * @param {*} characters_id 
 * @returns 
 */
export function get_characters_client_id(characters_id) {
    return _CharactersClientData.get(characters_id);
}

/**
 * 登录指定角色
 * @param {*} characters_id 
 */
export function login(characters_id) {
    set_characters_online(characters_id);
    let characters = _CharactersData.get(characters_id);
    //向地图内加入玩家
    G.MapUtils.add_characters(characters["地图数据"]["编号"], characters);
    G.EventCallback.publish_event("角色上线", [characters]);
}

/**
 * 指定角色退出登录
 * @param {*} characters_id 
 */
export function logout_characters(characters_id) {
    _OnlineCharactersData.delete(characters_id);
    let characters = _CharactersData.get(characters_id);
    if (characters !== undefined) {
        //从地图中删除
        G.MapUtils.remove_characters(characters["地图数据"]["编号"], characters["id"]);
        G.EventCallback.publish_event("角色离线", [characters]);
    }
}

/**
 * 设置在线角色缓存
 */
export function set_online_characters_cache(online_characters) {
    _global_.set_global_cache("online_characters", JSON.stringify(online_characters));
}

/**
 * 设置角色在线
 * @param {*} characters_id
 */
export function set_characters_online(characters_id) {
    _OnlineCharactersData.set(characters_id, 1);
}

/**
 * 角色是否已上线
 * @param {*} characters_id 
 */
export function check_characters_online(characters_id) {
    return _OnlineCharactersData.has(characters_id);
}


/**
 * 计算属性
 * @param zz 种族 
 * @param ww 五维 
 */
function computing_characters_attribute(zz, ww) {
    if (zz === "人" || zz === 1) {
        return {
            "命中": Math.ceil(ww["力量"] * 2.01 + 30),
            "伤害": Math.ceil(ww["力量"] * 0.67 + 60),
            "防御": Math.ceil(ww["耐力"] * 1.5),
            "速度": Math.ceil((ww["体质"] * 0.1) + (ww["耐力"] * 0.1) + (ww["力量"] * 0.1) + (ww["敏捷"] * 0.7)),
            "灵力": Math.ceil((ww["体质"] * 0.3) + (ww["魔力"] * 0.7) + (ww["耐力"] * 0.2) + (ww["力量"] * 0.4)),
            "躲避": Math.ceil(ww["敏捷"] + 10),
            "气血": Math.ceil((ww["体质"] * 5 + 100)),
            "法力": Math.ceil((ww["魔力"] * 3 + 100)),
        };
    }
    else if (zz === "魔" || zz === 2) {
        return {
            "命中": Math.ceil(ww["力量"] * 2.31 + 29),
            "伤害": Math.ceil(ww["力量"] * 0.77 + 60),
            "防御": Math.ceil(ww["耐力"] * 1.4),
            "速度": Math.ceil((ww["体质"] * 0.1) + (ww["耐力"] * 0.1) + (ww["力量"] * 0.1) + (ww["敏捷"] * 0.7)),
            "灵力": Math.ceil((ww["体质"] * 0.3) + (ww["魔力"] * 0.7) + (ww["耐力"] * 0.2) + (ww["力量"] * 0.4)),
            "躲避": Math.ceil(ww["敏捷"] + 10),
            "气血": Math.ceil((ww["体质"] * 6 + 100)),
            "法力": Math.ceil((ww["魔力"] * 2.5 + 100)),
        };
    } else if (zz === "仙" || zz === 3) {
        return {
            "命中": Math.ceil(ww["力量"] * 1.71 + 30),
            "伤害": Math.ceil(ww["力量"] * 0.57 + 60),
            "防御": Math.ceil(ww["耐力"] * 1.6),
            "速度": Math.ceil((ww["体质"] * 0.1) + (ww["耐力"] * 0.1) + (ww["力量"] * 0.1) + (ww["敏捷"] * 0.7)),
            "灵力": Math.ceil((ww["体质"] * 0.3) + (ww["魔力"] * 0.7) + (ww["耐力"] * 0.2) + (ww["力量"] * 0.4)),
            "躲避": Math.ceil(ww["敏捷"] + 10),
            "气血": Math.ceil((ww["体质"] * 4.5 + 100)),
            "法力": Math.ceil((ww["魔力"] * 3.5 + 100)),
        };
    } else {
        return {
            "命中": 0,
            "伤害": 0,
            "防御": 0,
            "速度": 0,
            "灵力": 0,
            "躲避": 0,
            "气血": 0,
            "法力": 0,
        };
    }
}

/**
 * 取技能等级
 * @param characters 角色数据
 * @param skill_type 技能类型
 * @param skill_name 技能名称
 */
export function get_skill_level(characters, skill_type, skill_name) {
    for (let index = 0; index < characters[skill_type].length; index++) {
        let element = characters[skill_type][index];
        if (element["名称"] === skill_name) {
            if (element["学会"]) {
                return element["等级"];
            }
            return 0;
        }
    }
    return 0;
}

/**
 * 获取门派秘籍技能等级
 * @param {*} characters_id 
 * @param {*} skill_name 
 */
export function get_sects_cheats_level(characters_id, skill_name) {
    let characters = _CharactersData.get(characters_id);
    if (characters !== undefined && characters["门派秘籍"] !== undefined) {
        return characters["门派秘籍"][skill_name] || 0;
    }
    return 0;
}


/**
 * 计算装备附加属性
 * @param {*} characters 
 */
function computing_equipment_attribute(characters) {
    let attribute_keys = ["命中", "躲避", "伤害", "防御", "魔法", "灵力", "气血", "体质", "魔力", "力量", "耐力", "敏捷", "速度", "固定伤害"];
    //重置 装备属性 套装属性
    characters["装备属性"] = {};
    characters["套装"] = {
        "名称": "无",
        "激活": 0,
        "属性": {},
    };
    for (let index = 0; index < attribute_keys.length; index++) {
        characters["装备属性"][attribute_keys[index]] = 0;
        characters["套装"]["属性"][attribute_keys[index]] = 0;
    }

    let combination_sum = new Map();
    if (characters["装备"]) {
        for (let index = 0; index < characters["装备"].length; index++) {
            const equipment = characters["装备"][index];
            if (equipment !== null) {
                //计算装备附加属性
                for (let attribute_index = 0; attribute_index < attribute_keys.length; attribute_index++) {
                    const attribute_key = attribute_keys[attribute_index];
                    if (equipment[attribute_key] !== undefined) {
                        characters["装备属性"][attribute_key] += equipment[attribute_key];
                    }
                }
                //统计套装数量
                if (equipment["套装效果"] !== undefined) {
                    if (combination_sum.has(equipment["套装效果"])) {
                        let combination = combination_sum.get(equipment["套装效果"]);
                        combination["sum"] += 1;
                    } else {
                        combination_sum.set(equipment["套装效果"], { "index": index, "sum": 1 });
                    }
                }
            }
        }
    }
    //计算套装效果
    for (let [key, value] of combination_sum) {
        if (value["sum"] >= 3) {
            characters["套装"]["名称"] = key;
            characters["套装"]["激活"] = 1;
            //取套装的其中一件装备
            let combination_equipment = characters["装备"][value["index"]];
            for (let index = 0; index < attribute_keys.length; index++) {
                const combination_attribute = combination_equipment["套装属性"][attribute_keys[index]];
                if (combination_attribute !== undefined) {
                    characters["套装"]["属性"][attribute_keys[index]] += combination_attribute;
                }
            }
            break;
        }
    }
    //TODO 计算装备符石属性
}

/**
 * 计算灵饰属性
 * @param {*} characters 
 */
function computing_ling_shi_attribute(characters) {
    //重置角色的灵饰战斗属性
    for (let index = 0; index < G.ItemUtils.ls_zdsx.length; index++) {
        const attribute_key = G.ItemUtils.ls_zdsx[index];
        characters[attribute_key] = 0;
    }

    //获取灵饰属性
    if (characters["灵饰"]) {
        for (let index = 0; index < characters["灵饰"].length; index++) {
            let ling_shi = characters["灵饰"][index];
            if (ling_shi !== null) {
                let attribute_key = ling_shi["幻化属性"]["基础"]["类型"];
                let attribute_value = ling_shi["幻化属性"]["基础"]["数值"];
                if (G.ItemUtils.ls_basic_attribute.includes(attribute_key)) {
                    //基础属性 计算到装备属性
                    characters["装备属性"][attribute_key] += attribute_value;
                } else {
                    //战斗属性 直接计算到角色本身
                    characters[attribute_key] += attribute_value;
                }
                for (let j = 0; j < ling_shi["幻化属性"]["附加"].length; j++) {
                    const sub_data = ling_shi["幻化属性"]["附加"][j];
                    let sub_attribute_key = sub_data["类型"];
                    let sub_attribute_value = sub_data["数值"];
                    if (G.ItemUtils.ls_basic_attribute.includes(sub_attribute_key)) {
                        //基础属性 计算到装备属性
                        characters["装备属性"][sub_attribute_key] += sub_attribute_value;
                    } else {
                        //战斗属性 直接计算到角色本身
                        characters[sub_attribute_key] += sub_attribute_value;
                    }
                }
            }
        }
    }
}

/**
 * 计算修身属性加成
 * @param {*} characters 
 */
function computing_xiu_shen_attribute(characters) {
    if (characters["修业"] && characters["修业"]["等级"] > 0) {
        characters["最大气血"] += characters["修业"]["等级"] * 8;
        characters["伤害"] += characters["修业"]["等级"] * 3;
        characters["法伤"] += characters["修业"]["等级"] * 10;
        characters["固定伤害"] += characters["修业"]["等级"] * 10;
        characters["速度"] += characters["修业"]["等级"] * 2;
    }
}

/**
 * 计算器灵效果属性影响
 * @param {*} characters 
 */
function computing_qi_ling_attribute(characters) {
    if (characters["器灵效果"]) {
        if (characters["器灵效果"]["金蝉"] === 2) {
            characters["速度"] += Math.floor(characters["速度"] * 0.03)
            characters["防御"] += Math.floor(characters["防御"] * 0.03)
            characters["最大气血"] += Math.floor(characters["防御"] * 0.03)
        }
        else if (characters["器灵效果"]["金蝉"] === 4) {
            characters["速度"] += Math.floor(characters["速度"] * 0.06)
            characters["防御"] += Math.floor(characters["防御"] * 0.06)
            characters["最大气血"] += Math.floor(characters["防御"] * 0.06)
        }
        else if (characters["器灵效果"]["金蝉"] === 6) {
            characters["速度"] += Math.floor(characters["速度"] * 0.08)
            characters["防御"] += Math.floor(characters["防御"] * 0.08)
            characters["最大气血"] += Math.floor(characters["防御"] * 0.08)
        }
        else if (characters["器灵效果"]["无双"] === 2) {
            characters["伤害"] += Math.floor(characters["伤害"] * 0.03)
            characters["灵力"] += Math.floor(characters["灵力"] * 0.03)
            characters["法伤"] += Math.floor(characters["法伤"] * 0.03)
            characters["封印命中等级"] += Math.floor(characters["封印命中等级"] * 0.08)
        }
        else if (characters["器灵效果"]["无双"] === 4) {
            characters["伤害"] += Math.floor(characters["伤害"] * 0.06)
            characters["灵力"] += Math.floor(characters["灵力"] * 0.06)
            characters["法伤"] += Math.floor(characters["法伤"] * 0.0063)
            characters["封印命中等级"] += Math.floor(characters["封印命中等级"] * 0.06)
        }
        else if (characters["器灵效果"]["无双"] === 6) {
            characters["伤害"] += Math.floor(characters["伤害"] * 0.08)
            characters["灵力"] += Math.floor(characters["灵力"] * 0.08)
            characters["法伤"] += Math.floor(characters["法伤"] * 0.08)
            characters["封印命中等级"] += Math.floor(characters["封印命中等级"] * 0.08)
        }
    }
}

/**
 * 计算器灵效果属性影响
 * @param {*} characters 
 */
function computing_ysys_attribute(characters) {
    if (characters["元素曜石"]) {
        characters["防御"] += Math.floor(characters["防御"] * characters["元素曜石"]["防御"]);
        characters["速度"] += Math.floor(characters["速度"] * characters["元素曜石"]["速度"]);
        characters["伤害"] += Math.floor(characters["伤害"] * characters["元素曜石"]["伤害"]);
        characters["固定伤害"] += Math.floor(characters["固定伤害"] * characters["元素曜石"]["固定伤害"]);
        characters["法伤"] += Math.floor(characters["法伤"] * characters["元素曜石"]["法伤"]);
        characters["封印命中等级"] += Math.floor(characters["封印命中等级"] * characters["元素曜石"]["封印命中等级"]);
    }
}

/**
 * 计算坐骑属性加成
 * @param {*} characters 
 */
function computing_mounts_attribute(characters) {
    //重置坐骑属性
    characters["坐骑属性"] = { "敏捷": 0, "体质": 0, "魔力": 0, "耐力": 0, "力量": 0 };

    //如果乘骑了坐骑
    if (characters["坐骑"] !== null && characters["坐骑"] !== undefined) {
        let mount_data = characters["坐骑"];
        //基础属性受等级影响
        let level = mount_data["等级"];
        for (let index = 0; index < G.Mounts.mounts_attribute_keys.length; index++) {
            const mounts_attribute_key = G.Mounts.mounts_attribute_keys[index];
            if (characters["坐骑属性"][mounts_attribute_key] === undefined) {
                characters["坐骑属性"][mounts_attribute_key] = 0;
            }
            characters["坐骑属性"][mounts_attribute_key] += level;
        }
        //根据好感度计算加成倍率
        let bonus = Math.min(mount_data["好感度"] * 0.01, 1);
        //成长值 受好感度影响
        let cz = (mount_data["初始成长"] + mount_data["额外成长"]) * bonus;
        //主属性额外加成
        if (mount_data["主属性"] !== null && mount_data["主属性"] !== undefined) {
            characters["坐骑属性"][mount_data["主属性"]] += level * 5;
        }
        //计算每一项坐骑属性加成
        characters["坐骑属性"]["体质"] = Math.floor(characters["坐骑属性"]["体质"] / 25 * cz);
        characters["坐骑属性"]["魔力"] = Math.floor(characters["坐骑属性"]["魔力"] / 31 * cz);
        characters["坐骑属性"]["力量"] = Math.floor(characters["坐骑属性"]["力量"] / 21 * cz);
        characters["坐骑属性"]["耐力"] = Math.floor(characters["坐骑属性"]["耐力"] / 24 * cz);
        characters["坐骑属性"]["敏捷"] = Math.floor(characters["坐骑属性"]["敏捷"] / 2335 * cz);
    }
}

/**
 * 计算变身属性
 * @param {*} characters 
 */
function computing_bian_shen_attribute(characters) {
}

/**
 * 计算法宝加成
 * @param {*} characters 
 */
function computing_fa_bao_attribute(characters) {
    characters["额外法宝等级"] = {};
    if (characters["法宝佩戴"] !== undefined) {
        for (let index = 0; index < characters["法宝佩戴"].length; index++) {
            const fb = characters["法宝佩戴"][index];
            if (fb && fb["魔法"] > 0) {
                if (fb["名称"] === "风袋") {
                    let values = { 1: 10, 2: 10, 3: 11, 4: 12, 5: 14, 6: 15, 7: 18, 8: 21, 9: 25 };
                    let jc = values[fb["境界"]] || 25;
                    if (fb["五行"] === "水") {
                        characters["速度"] += jc + 1;
                    } else if (fb["五行"] === "土") {
                        characters["速度"] += jc - 1;
                    } else {
                        characters["速度"] += jc;
                    }
                }
                if (fb["名称"] === "凌波仙符" && characters["门派"] === "凌波城") {
                    characters["速度"] += fb["境界"] * 2 + 4;
                    if (fb["五行"] === "金") {
                        characters["速度"] += 5;
                    }
                }
                if (fb["名称"] === "定风珠" && characters["门派"] === "五庄观") {
                    if (fb["境界"] <= 7) {
                        characters["额外法宝等级"]["乾坤袖"] = 1;
                    }
                    else {
                        characters["额外法宝等级"]["乾坤袖"] = 2;
                    }
                }
                if (fb["名称"] === "天师符" && characters["门派"] === "方寸山") {
                    if (fb["境界"] <= 7) {
                        characters["额外法宝等级"]["符之术"] = 1;
                    }
                    else {
                        characters["额外法宝等级"]["符之术"] = 2;
                    }
                }
                if (fb["名称"] === "织女扇" && characters["门派"] === "女儿村") {
                    if (fb["境界"] <= 7) {
                        characters["额外法宝等级"]["闭月羞花"] = 1;
                    }
                    else {
                        characters["额外法宝等级"]["闭月羞花"] = 2;
                    }
                }
                if (fb["名称"] === "雷兽" && characters["门派"] === "天宫") {
                    if (fb["境界"] <= 7) {
                        characters["额外法宝等级"]["乾坤塔"] = 1;
                    }
                    else {
                        characters["额外法宝等级"]["乾坤塔"] = 2;
                    }
                }
                if (fb["名称"] === "迷魂灯" && characters["门派"] === "盘丝洞") {
                    if (fb["境界"] <= 7) {
                        characters["额外法宝等级"]["迷情大法"] = 1;
                    }
                    else {
                        characters["额外法宝等级"]["迷情大法"] = 2;
                    }
                }
                if (fb["名称"] === "幽灵珠" && characters["门派"] === "无底洞") {
                    if (fb["境界"] <= 7) {
                        characters["额外法宝等级"]["阴风绝章"] = 1;
                    }
                    else {
                        characters["额外法宝等级"]["阴风绝章"] = 2;
                    }
                }
            }
        }
    }
}

/**
 * 计算神器属性
 * @param {*} characters 
 */
function computing_shen_qi_attribute(characters) {
    if (characters["神器"] && characters["神器"]["佩戴"]) {
        for (let index = 0; index < characters["神器"]["五行"].length; index++) {
            const element = characters["神器"]["五行"][index];
            if (element["属性"] === "气血") {
                characters["最大气血"] += element["属性"]["数值"];
            } else {
                if (!characters[element["属性"]]) {
                    characters[element["属性"]] = 0;
                }
                characters[element["属性"]] += element["数值"];
            }
        }
    }
}

/**
 * 角色属性实时计算算法
 * @param characters 角色数据 
 */
export function computing_characters_data(characters) {
    //计算装备附加属性
    computing_equipment_attribute(characters);
    //计算灵饰属性
    computing_ling_shi_attribute(characters);
    //计算坐骑属性
    computing_mounts_attribute(characters);

    //五庄观修身对五维属性影响
    let xs = characters["门派"] === "五庄观" && characters["修身"] === 1 ? 14 : 0;
    //五维属性 
    let five_attributes = computing_characters_attribute(characters["种族"],
        {
            "体质": characters["体质"] + characters["装备属性"]["体质"] + characters["坐骑属性"]["体质"] + characters["套装"]["属性"]["体质"] + xs,
            "魔力": characters["魔力"] + characters["装备属性"]["魔力"] + characters["坐骑属性"]["魔力"] + characters["套装"]["属性"]["魔力"] + xs,
            "力量": characters["力量"] + characters["装备属性"]["力量"] + characters["坐骑属性"]["力量"] + characters["套装"]["属性"]["力量"] + xs,
            "耐力": characters["耐力"] + characters["装备属性"]["耐力"] + characters["坐骑属性"]["耐力"] + characters["套装"]["属性"]["耐力"] + xs,
            "敏捷": characters["敏捷"] + characters["装备属性"]["敏捷"] + characters["坐骑属性"]["敏捷"] + characters["套装"]["属性"]["敏捷"] + xs,
        }
    );

    // TODO 精炼等级 锻体加成 待实现
    let dt = { "伤害": 0, "防御": 0, "灵力": 0, "魔法": 0, "气血": 0, "命中": 0, "体质": 0, "魔力": 0, "力量": 0, "耐力": 0, "敏捷": 0, "速度": 0, };

    // TODO 额外技能属性
    characters["额外技能属性"] = { "伤害": 0, "灵力": 0, "防御": 0, "命中": 0, "速度": 0, "气血": 0, "魔法": 0, "治疗能力": 0, "暗器防御": 0, "躲避": 0 };
    characters["命中"] = Math.floor(dt["命中"] + five_attributes["命中"] + characters["装备属性"]["命中"] + characters["技能属性"]["命中"] + characters["额外技能属性"]["命中"]);
    characters["伤害"] = Math.floor(dt["伤害"] + five_attributes["伤害"] + characters["装备属性"]["伤害"] + characters["技能属性"]["伤害"] + characters["额外技能属性"]["伤害"] + (characters["装备属性"]["命中"] / 3) + (characters["技能属性"]["命中"] / 3) + (characters["额外技能属性"]["命中"] / 3));
    characters["伤害"] += get_skill_level(characters, "强化技能", "伤害强化");
    //阴曹地府的黑夜伤害计算
    if (characters["门派"] === "阴曹地府") {
        let skill_level = get_skill_level(characters, "师门技能", "六道轮回");
        characters["黑夜伤害"] = Math.floor(G.Skill.computing_sects_skill(2.3766, 0.021073, skill_level)) - Math.floor(G.Skill.computing_sects_skill(1.46569, 0.0092, skill_level));
    }
    characters["防御"] = Math.floor(dt["防御"] + five_attributes["防御"] + characters["装备属性"]["防御"] + characters["技能属性"]["防御"] + characters["额外技能属性"]["防御"]);
    characters["防御"] += get_skill_level(characters, "强化技能", "防御强化");
    characters["速度"] = Math.floor(dt["敏捷"] + dt["速度"] + five_attributes["速度"] + characters["装备属性"]["速度"] + characters["技能属性"]["速度"] + characters["额外技能属性"]["速度"]);
    characters["速度"] += Math.floor(get_skill_level(characters, "辅助技能", "神速") * 1.5);
    characters["灵力"] = Math.floor(dt["灵力"] + five_attributes["灵力"] + characters["装备属性"]["灵力"] + characters["技能属性"]["灵力"] + characters["额外技能属性"]["灵力"]);
    characters["躲避"] = Math.floor(five_attributes["躲避"] + characters["装备属性"]["躲避"] + characters["技能属性"]["躲避"] + characters["额外技能属性"]["躲避"]);
    characters["最大气血"] = dt["气血"] + five_attributes["气血"] + characters["装备属性"]["气血"] + characters["技能属性"]["气血"] + characters["额外技能属性"]["气血"];
    let qss = get_skill_level(characters, "辅助技能", "强身术");
    let qz = get_skill_level(characters, "辅助技能", "强壮");
    let hsj = get_skill_level(characters, "师门技能", "傲世诀");
    characters["最大气血"] = Math.floor(characters["最大气血"] * (1 + (qss * 0.01 + hsj * 0.003)) + (qz * 15 * (1 + qss * 0.01)));
    characters["最大气血"] += get_skill_level(characters, "强化技能", "气血强化") * 10;
    characters["最大魔法"] = dt["魔法"] + five_attributes["法力"] + characters["装备属性"]["魔法"] + characters["技能属性"]["魔法"] + characters["额外技能属性"]["魔法"];
    let mx = get_skill_level(characters, "辅助技能", "冥想");
    let zyx = get_skill_level(characters, "辅助技能", "周易学");
    characters["最大魔法"] = Math.floor(characters["最大魔法"] * (1 + (mx * 0.01 + zyx * 0.005)));
    let yszd = get_skill_level(characters, "辅助技能", "养生之道");
    characters["最大活力"] = Math.floor(10 + characters["等级"] * 5 + yszd * 4);
    let jss = get_skill_level(characters, "辅助技能", "健身术");
    characters["最大活力"] = Math.floor(10 + characters["等级"] * 5 + jss * 4);
    let fsqh = get_skill_level(characters, "强化技能", "法伤强化");
    characters["法伤"] = characters["灵力"] + fsqh;
    let ffqh = get_skill_level(characters, "强化技能", "法防强化");
    characters["法防"] = characters["灵力"] + ffqh;
    let zlqh = get_skill_level(characters, "强化技能", "治疗强化");
    characters["治疗能力"] += characters["装备属性"]["治疗能力"] + zlqh;

    // TODO 加载变身属性
    computing_bian_shen_attribute(characters);

    // 加载经脉属性
    if (characters["门派"] !== "无门派" && characters["奇经八脉"]) {
        // 批量执行经脉属性算法
        let sects_jing_mai_data = G.JingMaiData.default[characters["门派"]];
        // 已点经脉
        for (const key in characters["奇经八脉"]) {
            if (characters["奇经八脉"][key] === 1 && sects_jing_mai_data[key] && sects_jing_mai_data[key]["角色属性加成"]) {
                sects_jing_mai_data[key]["角色属性加成"](characters);
            }
        }
    }

    // 	计算法宝属性
    computing_fa_bao_attribute(characters);

    // TODO 计算神器属性加成
    computing_shen_qi_attribute(characters);

    if (characters["气血"] <= 0) {
        characters["气血"] = characters["最大气血"];
    }
    characters["气血上限"] = characters["最大气血"];
    characters["魔法"] = characters["最大魔法"];
    characters["最大经验"] = G.CharactersExt.get_characters_level_exp(characters["等级"]);

    if (characters["门派"] === "方寸山" && characters["奇经八脉"]["斗法"] === 1) {
        characters["法伤"] = Math.floor(characters["法伤"] + characters["法术伤害"]);
        characters["封印命中等级"] += Math.floor(characters["装备属性"]["伤害"] * 0.12);
    } else if (characters["门派"] === "天宫" && characters["奇经八脉"]["月桂"] === 1) {
        characters["法伤"] = Math.floor(characters["法伤"] + characters["法术伤害"]);
        characters["封印命中等级"] += Math.floor(characters["装备属性"]["伤害"] * 0.12);
    } else {
        characters["法伤"] = Math.floor(characters["法伤"] + characters["法术伤害"]);
    }
    characters["法防"] = Math.floor(characters["法防"] + characters["法术防御"]);

    //修业加成计算
    computing_xiu_shen_attribute(characters);

    //器灵效果计算
    computing_qi_ling_attribute(characters);

    //元素曜石计算
    computing_ysys_attribute(characters);

    return characters;
}



/**
 * 构建一个全新的角色信息
 * @param {*} username 
 * @param {*} characters_name 
 * @param {*} characters_type 
 * @param {*} characters_color 
 * @returns 
 */
export function build_characters_data(username, characters_name, characters_type, characters_color) {
    let data = G.CharactersExt.get_init_characters_data(characters_type, characters_color);
    data["账号"] = username;
    data["名称"] = characters_name;
    return data;
}

/**
 * 检查等级上限 不可以升级则需要做一些提示
 * @param {*} characters 
 */
export function check_up_level(characters) {

    let character_client_id = get_characters_client_id(characters["id"]);

    let max_level = 144;

    if (characters["历劫"]["飞升"]) {
        max_level = 155
    }

    if (characters["历劫"]["渡劫"]) {
        max_level = 175
    }

    if (characters["门派"] === "无门派") {
        max_level = 10
    } else {
        // 检查师门技能等级是否达到要求
        let count = 5;

        let skill_level = Math.floor(characters["等级"] - characters["等级"] / 5 - 10);

        if (characters["师门技能"] !== undefined && Object.keys(characters["师门技能"]).length > 0) {
            characters["师门技能"].forEach(skill => {
                if (skill["等级"] >= skill_level) {
                    count++;
                }
            });
        }
        if (count < 5) {
            if (character_client_id !== undefined) {
                ClientUtils.send_basic_prompt(character_client_id, `继续升级需要5项师门等级≥ ${skill_level}`);
            }
            return false;
        }
    }
    if (characters["等级"] >= max_level) {
        //发送选择门派弹窗
        if (characters["门派"] === "无门派") {
            if (character_client_id !== undefined) {
                ClientUtils.send_basic_prompt(character_client_id, "您还没有门派,选择一个吧~");
                ClientUtils.send_client_message(character_client_id, 228, {});
            }
            return false;
        } else {
            if (character_client_id !== undefined) {
                ClientUtils.send_basic_prompt(character_client_id, "#Y等级已达上限,可能需要飞升或渡劫");
            }
            return false;
        }
    }
    if (characters["等级"] === 69) {
        if (character_client_id !== undefined) {
            ClientUtils.send_client_dialogue(character_client_id, "", "系统", "是否确定将等级提升至70级吗？", ["我已确认将等级提升至70", "我再考虑考虑！"], null, null, [1, 1, "系统"]);
        }
        return false;
    }
    if (characters["等级"] === 109) {
        if (character_client_id !== undefined) {
            ClientUtils.send_client_dialogue(character_client_id, "", "系统", "是否确定将等级提升至110级吗？", ["我已确认将等级提升至110", "我再考虑考虑！"], null, null, [1, 1, "系统"]);
        }
        return false;
    }
    if (characters["等级"] === 129) {
        if (character_client_id !== undefined) {
            ClientUtils.send_client_dialogue(character_client_id, "", "系统", "是否确定将等级提升至130级吗？", ["我已确认将等级提升至130", "我再考虑考虑！"], null, null, [1, 1, "系统"]);
        }
        return false;
    }
    return true;
}

/**
 * 角色手动升级
 * @param {*} characters 
 * @param {*} is_break 是否跳过升级校验
 */
export function up_level(characters, is_break = false) {
    //升级前先校验一下是否可以直接升级
    if (is_break || check_up_level(characters)) {
        return auto_up_level(characters);
    } else {
        return false;
    }
}

/**
  * 角色自动升级
  */
export function auto_up_level(characters) {
    let character_client_id = get_characters_client_id(characters["id"]);
    if (characters["等级"] > max_level) {
        if (character_client_id !== undefined) {
            ClientUtils.send_basic_prompt(character_client_id, "#Y/您当前等级已达到服务器上限");
        }
    } else if (characters["当前经验"] < characters["最大经验"]) {
        if (character_client_id !== undefined) {
            ClientUtils.send_basic_prompt(character_client_id, "升级经验不足");
        }
    } else {
        characters["等级"] += 1;
        characters["体质"] += 1;
        characters["魔力"] += 1;
        characters["力量"] += 1;
        characters["耐力"] += 1;
        characters["敏捷"] += 1;
        characters["潜力"] += 5;
        characters["最大体力"] += 10;
        characters["最大活力"] += 10;
        characters["当前经验"] = characters["当前经验"] - characters["最大经验"];
        characters["最大经验"] = G.CharactersExt.get_characters_level_exp(characters["等级"]);

        //如果已飞升
        if (characters["历劫"]["飞升"]) {
            let data = Math.round((characters["等级"] - 20) / 5);
            if (data > 20) {
                data = 20;
            }
            for (const key in characters["修炼"]) {
                console.debug(key)
                if (typeof characters["修炼"][key] === "object") {
                    characters["修炼"][key][2] = data;
                }
            }
            for (const key in characters["bb修炼"]) {
                if (typeof characters["bb修炼"][key] === "object") {
                    characters["bb修炼"][key][2] = data;
                }
            }
        }

        let qyd_data = 0;
        if (characters["等级"] >= 69 && characters["等级"] < 89) {
            qyd_data = 2;
        } else if (characters["等级"] >= 89 && characters["等级"] < 109) {
            qyd_data = 3;
        } else if (characters["等级"] >= 109 && characters["等级"] < 129) {
            qyd_data = 4;
        } else if (characters["等级"] >= 129 && characters["等级"] < 155) {
            qyd_data = 5;
        } else if (characters["等级"] >= 155 && characters["等级"] < 159) {
            qyd_data = 6;
        } else if (characters["等级"] >= 159 && characters["等级"] < 164) {
            qyd_data = 7;
        } else if (characters["等级"] >= 164 && characters["等级"] < 168) {
            qyd_data = 8;
        } else if (characters["等级"] >= 168 && characters["等级"] < 171) {
            qyd_data = 9;
        } else if (characters["等级"] >= 171) {
            qyd_data = 9;
        }
        characters["QYD"]["可换乾元丹"] = (qyd_data - characters["QYD"]["已换乾元丹"]);

        //加点方案重置
        characters["加点方案"][0]["潜力"] = characters["潜力"];
        //播放升级动画
        if (character_client_id !== undefined) {
            ClientUtils.send_client_message(character_client_id, 36, { "动画": "升级" });
            //通知客户端更新角色数据
            ClientUtils.send_client_message(character_client_id, 31, computing_characters_data(characters));
            //更新剧情
            ClientUtils.send_characters_client_message(character_client_id, 227, characters["剧情"]);
            //刷新人物
            G.CharactersTask.refrush_task(characters["id"]);
        }
        G.MapUtils.send_play(characters["id"], "升级");
        return true;
    }
    return false;
}

/**
 * 添加经验
 * @param {*} characters_id 
 * @param {*} exp 
 */
export function add_exp(characters_id, exp) {
    let characters = _CharactersData.get(characters_id);
    characters["当前经验"] += exp;
    let character_client_id = get_characters_client_id(characters_id);
    if (character_client_id !== undefined) {
        ClientUtils.send_basic_prompt(character_client_id, `获得经验#G${exp}`);
        G.ChatUtils.send_system_chat(character_client_id, `获得经验#G${exp}`);
        //通知客户端更新角色数据
        ClientUtils.send_client_message(character_client_id, 31, computing_characters_data(characters));
    }
    //添加参战召唤兽的经验
    if (characters["参战宝宝"] !== undefined && Object.keys(characters["参战宝宝"]).length > 0) {
        G.Pet.add_exp(get_characters_fight_pet_data(characters), exp);
    }
}

/**
 * 减少经验
 * @param {*} characters_id 
 * @param {*} exp 
 */
export function remove_exp(characters_id, exp) {
    let characters = _CharactersData.get(characters_id);
    characters["当前经验"] -= exp;
    let character_client_id = get_characters_client_id(characters_id);
    if (character_client_id !== undefined) {
        ClientUtils.send_basic_prompt(character_client_id, `失去经验#G${exp}`);
        G.ChatUtils.send_system_chat(character_client_id, `失去经验#G${exp}`);
        //通知客户端更新角色数据
        ClientUtils.send_client_message(character_client_id, 31, computing_characters_data(characters));
    }
    //添加参战召唤兽的经验
    if (characters["参战宝宝"] !== undefined && Object.keys(characters["参战宝宝"]).length > 0) {
        G.Pet.add_exp(get_characters_fight_pet_data(characters), exp);
    }
}

/**
 * 添加剧情点
 * @param {*} characters_id 
 * @param {*} num 
 */
export function add_plot_point(characters_id, num) {
    _CharactersData.get(characters_id)["剧情点"]["总额"] += num;
    let character_client_id = get_characters_client_id(characters_id);
    if (character_client_id !== undefined) {
        ClientUtils.send_basic_prompt(character_client_id, `获得剧情点#G${num}`);
        G.ChatUtils.send_system_chat(character_client_id, `获得剧情点#G${num}`);
    }
}


/**
 * 增加某个字段值的数量
 * @param {*} characters_id 
 * @param {*} key 类型 
 * @param {*} num 数量
 */
export function add_number_field_value(characters_id, key, num) {
    if (_CharactersData.get(characters_id)[key] === undefined) {
        _CharactersData.get(characters_id)[key] = 0;
    }
    _CharactersData.get(characters_id)[key] += num;
    let character_client_id = get_characters_client_id(characters_id);
    if (character_client_id !== undefined) {
        ClientUtils.send_basic_prompt(character_client_id, `获得 #Y${num}#R${key}`);
        G.ChatUtils.send_system_chat(character_client_id, `获得 #Y${num}#R${key}`);
    }
}

/**
 * 减少某个字段值的数量
 * @param {*} characters_id 
 * @param {*} key 类型 
 * @param {*} num 数量
 */
export function remove_number_field_value(characters_id, key, num) {
    _CharactersData.get(characters_id)[key] -= num;
    if (_CharactersData.get(characters_id)[key] <= 0) {
        _CharactersData.get(characters_id)[key] = 0;
    }
    let character_client_id = get_characters_client_id(characters_id);
    if (character_client_id !== undefined) {
        ClientUtils.send_basic_prompt(character_client_id, `失去 #Y${num}#R${key}`);
        G.ChatUtils.send_system_chat(character_client_id, `失去 #Y${num}#R${key}`);
    }
}

/**
 * 获取角色状态
 */
export function get_characters_online_status(characters) {
    let online_text = "在线";
    if (characters["队伍"] !== 0 && _TeamDataCache.has(characters["队伍"])) {
        online_text = "队伍中";
    } else if (characters["摊位数据"] !== undefined && Object.keys(characters["摊位数据"]).length > 0) {
        online_text = "摆摊中";
    } else if (characters["战斗开关"] !== 0 && _FightDataCache.has(characters["战斗开关"])) {
        online_text = "战斗中";
    } else if (characters["观战状态"] !== undefined && characters["观战状态"] !== 0 && _FightDataCache.has(characters["观战状态"])) {
        online_text = "观战中";
    }
    return online_text;
}

/**
 * 获取角色在队伍中展示的数据
 * @param {*} characters_id 
 * @returns 
 */
export function build_team_data(characters_id) {
    let characters = _CharactersData.get(characters_id);
    return {
        "名称": characters["名称"],
        "门派": characters["门派"],
        "id": characters["id"],
        "等级": characters["等级"],
        "锦衣": characters["锦衣"],
        "炫彩": characters["炫彩"],
        "炫彩组": characters["炫彩组"],
        "染色方案": characters["染色方案"],
        "染色组": characters["染色组"],
        "模型": characters["模型"],
        "当前称谓": characters["当前称谓"],
        "变身数据": characters["变身数据"],
        "坐骑": characters["坐骑"],
    };
}

/**
 * 通知客户端刷新气血数据
 * @param {*} characters_id 
 */
export function refrush_hp_data(characters_id) {
    let characters = _CharactersData.get(characters_id);
    let computing_data = computing_characters_data(characters);
    let end_data = [{
        "气血": computing_data["气血"],
        "气血上限": computing_data["气血上限"],
        "最大气血": computing_data["最大气血"],
        "魔法": computing_data["魔法"],
        "最大魔法": computing_data["最大魔法"],
        "愤怒": computing_data["愤怒"],
    }];
    let character_client_id = get_characters_client_id(characters_id);
    if (character_client_id !== undefined) {
        ClientUtils.send_client_message(character_client_id, 47, end_data);
    }
}


/**
 * 通知客户端刷新道具数据
 * @param {*} characters_id 
 */
export function refrush_item_data(characters_id, item_key_list) {
    let characters = _CharactersData.get(characters_id);
    let send_data = {};
    for (let index = 0; index < item_key_list.length; index++) {
        let item_key = item_key_list[index];
        send_data[item_key] = characters[item_key];
    }
    ClientUtils.send_characters_client_message(characters_id, 14, send_data);
}

/**
 * 召唤兽参战
 * @param {*} characters_id 
 * @param {*} pet_data 
 * @param {*} index 
 * @returns 
 */
export function enable_pet_fight(characters_id, pet_data, index) {
    let characters = _CharactersData.get(characters_id);
    if (characters !== undefined) {
        if (characters["参战宝宝"] !== undefined && characters["参战宝宝"]["index"] === index) {
            characters["参战宝宝"] = undefined;
            pet_data["参战信息"] = 0;
            ClientUtils.send_characters_basic_prompt(characters_id, "取消参战成功");
            ClientUtils.send_characters_client_message(characters_id, 16, characters["召唤兽"]);
            ClientUtils.send_characters_client_message(characters_id, 18, characters["参战宝宝"]);
            return;
        }
        if (characters["参战宝宝"] !== undefined && characters["召唤兽"][characters["参战宝宝"]["index"]] !== undefined) {
            characters["召唤兽"][characters["参战宝宝"]["index"]]["参战信息"] = 0;
        }
        pet_data["参战信息"] = 1;
        // if(pet_data["参战等级"] - login_characters["等级"] > 10){
        //     ClientUtils.send_basic_prompt(client_id, "与召唤兽相差超过十级,无法参战。");
        //     return;
        // }
        update_fight_pet(characters, pet_data, index);
        ClientUtils.send_characters_basic_prompt(characters_id, "参战成功");
        ClientUtils.send_characters_client_message(characters_id, 16, characters["召唤兽"]);
        ClientUtils.send_characters_client_message(characters_id, 18, characters["参战宝宝"]);
    }
}

/**
 * 更新参战宝宝信息
 * @param {*} characters 
 * @param {*} pet_data 
 * @param {*} index 
 */
export function update_fight_pet(characters, pet_data, index) {
    characters["参战宝宝"] = {
        "名称": pet_data["名称"],
        "等级": pet_data["等级"],
        "模型": pet_data["模型"],
        "染色方案": pet_data["染色方案"],
        "染色组": pet_data["染色组"],
        "气血": pet_data["气血"],
        "最大气血": pet_data["最大气血"],
        "魔法": pet_data["魔法"],
        "最大魔法": pet_data["最大魔法"],
        "当前经验": pet_data["当前经验"],
        "最大经验": pet_data["最大经验"],
        "认证码": pet_data["认证码"],
        "index": index,
    };
}

/**
 * 添加称谓
 * @param {*} characters_id 
 * @param {*} chengwei 
 */
export function add_chengwei(characters_id, chengwei) {
    let characters = _CharactersData.get(characters_id);
    let chengwei_set = new Set(characters["称谓"]);
    chengwei_set.add(chengwei)
    characters["称谓"] = Array.from(chengwei_set);
    ClientUtils.send_characters_basic_prompt(characters_id, `你获得了新的称谓 #R ${chengwei}`);
}

/**
 * 删除称谓
 * @param {*} characters_id 
 * @param {*} chengwei 
 */
export function remove_chengwei(characters_id, chengwei) {
    let characters = _CharactersData.get(characters_id);
    let chengwei_set = new Set(characters["称谓"]);
    chengwei_set.delete(chengwei);
    characters["称谓"] = Array.from(chengwei_set);
    ClientUtils.send_characters_basic_prompt(characters_id, "你失去了一个称谓");
    if (characters["当前称谓"] === chengwei) {
        characters["当前称谓"] = "";
        G.MapUtils.update_chengwei(characters_id);
    }
}

/**
 * 设置技能快捷键
 */
export function set_set_shortcut_key(characters_id, keyboard_key, name, type) {
    let characters = _CharactersData.get(characters_id);
    let index = keyboard_key_index[keyboard_key];
    characters["快捷技能"][index] = { "名称": name, "类型": type };
    ClientUtils.send_characters_client_message(characters_id, 42, characters["快捷技能"]);
}

/**
 * 是否可以飞行
 * @param {*} characters 
 * @returns 
 */
export function check_flight(characters) {
    if (characters["坐骑"] === undefined || characters["坐骑"] === null) {
        return [false, "#Y/未骑乘坐骑"];
    }
    if (characters["队伍"] !== 0 && !characters["队长"]) {
        return [false, "#Y/只有队长才可以使用飞行功能"];
    }
    if (desable_flight_map.includes(characters["地图数据"]["编号"])) {
        return [false, "#Y/此场景无法使用飞行功能"];
    }
    return [true, ""];
}

/**
 * 修改飞行状态
 * @param {*} characters_id 
 * @returns 
 */
export function update_flight(characters_id) {
    let characters = _CharactersData.get(characters_id);
    //未飞行代表需要启动飞行
    if (!characters["飞行中"]) {
        let res = check_flight(characters);
        if (!res[0]) {
            ClientUtils.send_characters_basic_prompt(characters_id, res[1]);
            return;
        }
    }
    if (characters["队伍"] === 0) {
        let message = characters["飞行中"] ? "#Y/你落地了..." : "#Y/你飞了起来...";
        characters["飞行中"] = !characters["飞行中"];
        ClientUtils.send_characters_basic_prompt(characters["id"], message);
        ClientUtils.send_characters_client_message(characters["id"], 4020, { "逻辑": characters["飞行中"] });
        G.MapUtils.update_characters_flight(characters_id);
    } else {
        characters["飞行中"] = !characters["飞行中"];
        G.TeamUtils.sync_team_flight(characters["队伍"]);
    }
}

/**
 * 重新设置门派技能
 */
export function reset_sects_skill(characters) {
    characters["师门技能"] = [];
    let sects_skill_names = G.Sects.sects_skill[characters["门派"]];
    for (let index = 0; index < sects_skill_names.length; index++) {
        const sikll_name = sects_skill_names[index];
        characters["师门技能"][index] = {
            "名称": sikll_name,
            "学会": false,
            "包含技能": {},
            "等级": 79,
        }
        G.Skill.up_skill_level(characters, index);
    }
}

/**
 * 加入帮派
 * @param {*} characters_id 
 */
export function join_sects(characters_id, sects_name) {
    let characters = _CharactersData.get(characters_id);
    if (characters["等级"] < 10) {
        ClientUtils.send_characters_basic_prompt(characters_id, "等级不足10级");
        return;
    }
    if (characters["门派"] !== "无门派") {
        ClientUtils.send_characters_basic_prompt(characters_id, "你已经投入其它门派");
        return;
    }
    if (characters["模型"] !== "影精灵" && !G.Sects.check_join_sects(characters, sects_name)) {
        ClientUtils.send_characters_basic_prompt(characters_id, "本门派不收你这样的弟子");
        return;
    } else if (characters["模型"] === "影精灵" && characters["门派"] !== "九黎城") {
        ClientUtils.send_characters_basic_prompt(characters_id, "影精灵只可以加入九黎城");
        return;
    }
    characters["门派"] = sects_name;
    ClientUtils.send_characters_basic_prompt(characters_id, `你已成为#R/${sects_name}#Y/弟子`);
    characters["奇经八脉"] = G.Sects.sects_jingmai[sects_name];
    reset_sects_skill(characters);
    characters["招式特效"] = G.Sects.build_sects_special_effects(sects_name);

    // 	if 玩家数据[id].角色.武神坛角色){ //武神坛
    // 		玩家数据[id].神器:添加神器(id)
    // 	}
    // }
    G.Sects.send_join_sects_reward(characters_id);
    let last_dialogue = _LastDialogueData.get(characters_id);
    ClientUtils.send_characters_client_dialogue(characters_id, last_dialogue["模型"], last_dialogue["名称"], "既然你诚心要拜入本门派，那我就收你为徒。从即日起，我就是你的师傅了。你可要好好得尊师重道。这点礼物是为师的一点心意。")
    refrush_characters_data(characters);
    //删除临时剧情
    ClientUtils.send_characters_client_message(characters_id, 227, {
        "主线": 2,
        "编号": 1,
        "地图": G.MapUtils.sect_map_data[sects_name][0],
        "进度": 2222,
        "附加": {},
        "移除": true,
    });
    //刷新角色原剧情
    characters["剧情"] = {
        "主线": 2,
        "编号": 9,
        "地图": 1501,
        "进度": 2,
        "附加": {}
    };
    ClientUtils.send_characters_client_message(characters_id, 227, characters["剧情"]);
}

/**
 * 消耗指定的属性值
 */
export function consume_number_field_value(characters_id, key, num) {
    let characters = _CharactersData.get(characters_id);
    if (characters[key] > num) {
        characters[key] -= num;
        return true;
    }
    return false;
}

/**
 * 刷新法宝背包
 */
export function refrush_fabao_data(characters) {
    let send_data = {
        "法宝": characters["法宝"],
        "佩戴": characters["法宝佩戴"],
        "灵宝": characters["灵宝"],
        "灵宝佩戴": characters["灵宝佩戴"],
    };
    if (characters["神器"] && characters["门派"] !== "无门派") {
        send_data["是否有神器"] = true;
        send_data["是否佩戴神器"] = characters["神器"]["佩戴"];
        send_data["神器格子"] = characters["神器"]["位置"];
    }
    ClientUtils.send_characters_client_message(characters["id"], 3527, send_data);
}

/**
 * 添加神器
 * @param {*} characters_id 
 */
export function add_shenqi(characters_id) {
    let characters = _CharactersData.get(characters_id);
    let data = G.ItemUtils.build_shenqi_attributes(characters["门派"]);
    characters["神器"] = data;
    refrush_fabao_data(characters);
}

/**
 * 刷新角色数据
 */
export function refrush_characters_data(characters) {
    ClientUtils.send_characters_client_message(characters["id"], 31, computing_characters_data(characters));
}

/**
 * 刷新角色面板数据
 */
export function refrush_characters_ui_data(characters) {
    ClientUtils.send_characters_client_message(characters["id"], 10, computing_characters_data(characters));
}

/**
 * 获取主登录角色id
 * @param {*} characters_id 
 * @returns 
 */
export function get_master_characters_id(characters_id) {
    let characters = _CharactersData.get(characters_id)
    if (characters !== undefined) {
        let client_id = _UserNameClientData.get(characters["账号"]);
        let master_characters_id = _MasterCharactersData.get(client_id);
        let master_characters = _CharactersData.get(master_characters_id);
        if (master_characters !== undefined) {
            return master_characters["id"];
        }
    }
    return undefined;
}

/**
 * 获取角色所有穿戴装备的特技
 * @param {*} characters_id 
 */
export function get_equipment_ex_skill(characters_id) {
    let data = new Set();
    let characters = _CharactersData.get(characters_id);
    for (let index = 0; index < characters["装备"].length; index++) {
        let equipment = characters["装备"][index];
        if (equipment !== null && equipment["特技"] !== undefined) {
            data.add(equipment["特技"]);
        }
    }
    return Array.from(data);
}

/**
 * 获取角色所有穿戴装备的特效
 * @param {*} characters_id 
 */
export function get_equipment_effect(characters_id) {
    let data = new Set();
    let characters = _CharactersData.get(characters_id);
    for (let index = 0; index < characters["装备"].length; index++) {
        let equipment = characters["装备"][index];
        if (equipment !== null && equipment["特效"] !== undefined) {
            equipment["特效"].forEach(e => {
                data.add(e);
            })
        }
    }
    return Array.from(data);
}


/**
 * 获得参战宠物详细信息
 * @param {*} characters 
 * @returns 
 */
export function get_characters_fight_pet_data(characters) {
    let bb_index = characters["参战宝宝"]["index"];
    return characters["召唤兽"][bb_index];
}

const all_items_key = ["道具", "行囊", "任务"];

/**
 * 判断角色背包内指定物品的数量信息 每个背包下的总数和下标位置以及每个位置的物品数量
 * @param {*} characters_id 
 * @param {*} item_name 
 * @param {*} key 
 */
export function check_item(characters_id, item_name, key = "all") {
    let characters = _CharactersData.get(characters_id);
    let total_data = {};
    if (key === "all") {
        for (let index = 0; index < all_items_key.length; index++) {
            let key = all_items_key[index];
            let res = G.ItemsUils.check_items_exist_item(characters[key], item_name);
            if (res["总数"] > 0) {
                total_data[key] = res;
            }
        }
        return total_data;
    } else {
        let res = G.ItemsUils.check_items_exist_item(characters[key], item_name);
        return { key: res };
    }
}

/**
 * 同步角色道具效果
 * @param {*} characters 
 */
export function sync_characters_item_status(characters) {
    // 罗羹效果
    let task_data = G.CharactersTask.get_task_by_number(characters["id"], 10);
    if (task_data) {
        if (task_data["气血"] > 0 && characters["气血"] < characters["最大气血"]) {
            let hp = characters["最大气血"] - characters["气血"];
            if (task_data["气血"] > hp) {
                task_data["气血"] -= hp;
                characters["气血"] = characters["最大气血"];
            } else {
                task_data["气血"] = 0;
                characters["气血"] += task_data["气血"];
            }
        }
        if (task_data["魔法"] > 0 && characters["魔法"] < characters["最大魔法"]) {
            let mp = characters["最大魔法"] - characters["魔法"];
            if (task_data["魔法"] > mp) {
                task_data["魔法"] -= mp;
                characters["魔法"] = characters["最大魔法"];
            } else {
                task_data["魔法"] = 0;
                characters["魔法"] += task_data["魔法"];
            }
        }
        G.CharactersTask.refrush_task(characters["id"]);
    }
}

/**
 * 自动提交剧情物品
 * @param {*} characters_id 
 */
export function auto_submit_plot_item(characters_id) {
    let characters = _CharactersData.get(characters_id);
    if (characters["剧情"]["给予"]) {
        return true;
    }
    let money = characters["剧情"]["附加"]["银子"];
    if (money) {
        if (characters["银子"] < characters["剧情"]["附加"]) {
            ClientUtils.send_characters_basic_prompt(characters_id, `银子不足${money}`);
            return false;
        }
        G.Characters.remove_number_field_value(characters_id, "银子", money);
    }
    let plot_item_items = characters["剧情"]["附加"]["物品"];
    if (plot_item_items) {
        let consummer_data = [];
        // 检查每一样物品在背包内是否足够
        for (const submit_item_name in plot_item_items) {
            // 需要提交的数量
            let submit_num = plot_item_items[submit_item_name];
            let res = check_item(characters_id, submit_item_name, "all");
            // 累计提交的数量
            let submit_count = 0;
            // 遍历每一个背包
            for (const items_key in res) {
                // 背包内存在物品则遍历背包
                if (res[items_key]["总数"] > 0) {
                    // 遍历每一个位置下的物品统计信息
                    for (let index = 0; index < res[items_key]["详情"].length; index++) {
                        let element = res[items_key]["详情"][index];
                        // 位置
                        let item_index = element[0];
                        // 数量
                        let item_num = element[1];
                        // 如果物品数量大于等于需要提交数量则可以直接结束循环
                        if (item_num >= submit_num) {
                            consummer_data.push([items_key, item_index, submit_num]);
                            submit_count += submit_num;
                            break;
                        } else {
                            // 数量不够,取完位置后继续往下找
                            consummer_data.push([items_key, item_index, item_num]);
                            submit_count += item_num;
                        }
                    }
                    // 如果取完物品则直接结束该背包的遍历
                    if (submit_count === submit_num) {
                        break;
                    }
                }
                // 如果取完物品则直接结束所有背包的遍历
                if (submit_count === submit_num) {
                    break;
                }
            }
            // 校验物品数量是否满足提交要求
            if (submit_count < submit_num) {
                return submit_item_name;
            }
        }
        // 从背包中移除要提交的物品
        for (let index = 0; index < consummer_data.length; index++) {
            let element = consummer_data[index];
            let items_key = element[0];
            let item_index = element[1];
            let item_num = element[2];
            G.Characters.remove_item(characters_id, items_key, item_index, item_num);
        }
    }
    characters["剧情"]["给予"] = true;
    return true;
}

export function get_pet_data_by_number(characters, pet_number) {
    for (let index = 0; index < characters["召唤兽"].length; index++) {
        let pet_data = characters["召唤兽"][index];
        if (pet_data["认证码"] === pet_number) {
            return pet_data;
        }
    }
}

/**
 * 添加修炼经验
 * @param {*} characters_id 
 * @param {*} exp 
 * @returns 
 */
export function add_xl_exp(characters_id, exp) {
    let characters = _CharactersData.get(characters_id);
    let xl_key = characters["修炼"]["当前"];
    if (characters["修炼"][xl_key][0] >= characters["修炼"][xl_key][2]) {
        ClientUtils.send_characters_basic_prompt(characters_id, `#Y/你的${xl_key}等级已达上限，无法继续获得修炼经验`);
        return false;
    }
    let up_exp = computing_xl_exp(characters["修炼"][xl_key][0], characters["修炼"][xl_key][2]);
    if (characters["修炼"][xl_key][2] !== 0 && characters["修炼"][xl_key][1] >= up_exp) {
        ClientUtils.send_characters_basic_prompt(characters_id, `#Y/你的${xl_key}经验已达上限，无法继续获得修炼经验`);
        return false;
    }
    characters["修炼"][xl_key][1] += exp;
    ClientUtils.send_characters_basic_prompt(characters_id, `#Y/你的${xl_key}经验增加了${exp}点`);
    if (characters["修炼"][xl_key][1] >= up_exp) {
        characters["修炼"][xl_key][1] -= up_exp;
        characters["修炼"][xl_key][0] += 1;
        ClientUtils.send_characters_basic_prompt(characters_id, `#Y/你的${xl_key}等级提升至${characters["修炼"][xl_key][0]}级`);
    }
    ClientUtils.send_characters_client_message(characters_id, 44, { "人物": characters["修炼"], "bb": characters["bb修炼"] });
    return true;
}

/**
 * 添加召唤兽修炼经验
 * @param {*} characters_id 
 * @param {*} exp 
 * @returns 
 */
export function add_pet_xl_exp(characters_id, exp) {
    let characters = _CharactersData.get(characters_id);
    let xl_key = characters["修炼"]["当前"];
    if (characters["修炼"][xl_key][0] >= characters["修炼"][xl_key][2]) {
        ClientUtils.send_characters_basic_prompt(characters_id, `#Y/你的召唤兽${xl_key}等级已达上限，无法继续获得修炼经验`);
        return false;
    }
    let up_exp = computing_xl_exp(characters["修炼"][xl_key][0], characters["修炼"][xl_key][2]);
    if (characters["修炼"][xl_key][2] !== 0 && characters["修炼"][xl_key][1] >= up_exp) {
        ClientUtils.send_characters_basic_prompt(characters_id, `#Y/你的召唤兽${xl_key}经验已达上限，无法继续获得修炼经验`);
        return false;
    }
    characters["修炼"][xl_key][1] += exp;
    ClientUtils.send_characters_basic_prompt(characters_id, `#Y/你的召唤兽${xl_key}经验增加了${exp}点`);
    if (characters["修炼"][xl_key][1] >= up_exp) {
        characters["修炼"][xl_key][1] -= up_exp;
        characters["修炼"][xl_key][0] += 1;
        ClientUtils.send_characters_basic_prompt(characters_id, `#Y/你的召唤兽${xl_key}等级提升至${characters["修炼"][xl_key][0]}级`);
    }
    ClientUtils.send_characters_client_message(characters_id, 44, { "人物": characters["修炼"], "bb": characters["bb修炼"] });
    return true;
}

function computing_xl_exp(level, max) {
    if (level === 0) {
        return 110;
    }
    let exp = 110;
    for (let index = 1; index < max + 1; index++) {
        exp += 20 + index * 20;
        if (index === level) {
            return exp;
        }
    }
}